package com.javabi.common.concurrent.collect.readwrite;

import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import com.google.common.collect.ForwardingSet;

public abstract class ReadWriteForwardingSet<E> extends ForwardingSet<E> {

	private final transient ReadWriteLock lock;
	private final transient Lock readLock;
	private final transient Lock writeLock;

	protected ReadWriteForwardingSet(boolean fair) {
		this.lock = new ReentrantReadWriteLock(fair);
		this.readLock = lock.readLock();
		this.writeLock = lock.writeLock();
	}

	protected ReadWriteForwardingSet() {
		// Default to fair locking ...
		// write locks must be able to lock in a timely manner
		this(true);
	}

	public Lock getReadLock() {
		return readLock;
	}

	public Lock getWriteLock() {
		return writeLock;
	}

	@Override
	public int size() {
		Lock lock = getReadLock();
		lock.lock();
		try {
			return super.size();
		} finally {
			lock.unlock();
		}
	}

	@Override
	public boolean isEmpty() {
		Lock lock = getReadLock();
		lock.lock();
		try {
			return super.isEmpty();
		} finally {
			lock.unlock();
		}
	}

	@Override
	public boolean contains(Object element) {
		Lock lock = getReadLock();
		lock.lock();
		try {
			return super.contains(element);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public Iterator<E> iterator() {
		Lock lock = getReadLock();
		lock.lock();
		try {
			return super.iterator();
		} finally {
			lock.unlock();
		}
	}

	@Override
	public Object[] toArray() {
		Lock lock = getReadLock();
		lock.lock();
		try {
			return super.toArray();
		} finally {
			lock.unlock();
		}
	}

	@Override
	public <T> T[] toArray(T[] array) {
		Lock lock = getReadLock();
		lock.lock();
		try {
			return super.toArray(array);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public boolean add(E element) {
		Lock lock = getReadLock();
		lock.lock();
		try {
			return super.add(element);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public boolean remove(Object element) {
		Lock lock = getWriteLock();
		lock.lock();
		try {
			return super.remove(element);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public boolean containsAll(Collection<?> collection) {
		Lock lock = getReadLock();
		lock.lock();
		try {
			return super.containsAll(collection);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public boolean addAll(Collection<? extends E> collection) {
		Lock lock = getWriteLock();
		lock.lock();
		try {
			return super.addAll(collection);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public boolean removeAll(Collection<?> collection) {
		Lock lock = getWriteLock();
		lock.lock();
		try {
			return super.removeAll(collection);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public boolean retainAll(Collection<?> collection) {
		Lock lock = getWriteLock();
		lock.lock();
		try {
			return super.retainAll(collection);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public void clear() {
		Lock lock = getWriteLock();
		lock.lock();
		try {
			super.clear();
		} finally {
			lock.unlock();
		}
	}

}
